package mqtt_thingsboard_connector

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"go-iot-gateway/internal/apk/binarys"
	"go-iot-gateway/internal/conf_table"
	conf_table_define "go-iot-gateway/internal/conf_table/define"
	"go-iot-gateway/internal/storage"
	storage_define "go-iot-gateway/internal/storage/define"
	sys_contant "go-iot-gateway/internal/sys/contant"
	"strconv"
	"strings"
	"time"
)

// 最大通道任务数
var MaxRpcChan = 100

// rpcMaxTaskPool rpc 最大任务数(并发数)
var rpcMaxTaskPool = 10

// RPCRequest rpc 请求对象
// {"device":"箱变1号","data":{"id":3,"method":"sendCommand","params":{"command":"a"}}}
// {"device":"箱变1号","data":{"id":3,"method":"sendCommand","params":0}}
type RPCRequest struct {
	Device string `json:"device"`
	Data   struct {
		Id     uint64      `json:"id"`
		Method string      `json:"method"`
		Params interface{} `json:"params"`
	} `json:"data"`
}

// RPCResponseMsg 消息封装
// {"device": "箱变1号", "id": 1, "data": {"success": true}}
func RPCResponseMsg(req *RPCRequest, data map[string]interface{}) ([]byte, error) {

	if data == nil {
		data = map[string]interface{}{}
	}

	body := map[string]interface{}{
		"device": req.Device,
		"id":     req.Data.Id,
		"data":   data,
	}

	return json.Marshal(body)
}

func RPCResponseFailMsg(req *RPCRequest, failMsg string) []byte {
	msg, _ := RPCResponseMsg(req, map[string]interface{}{
		"success": false,
		"msg":     failMsg,
	})
	return msg
}

func RPCResponseSuccessMsg(req *RPCRequest, data map[string]interface{}) []byte {
	_data := make(map[string]interface{}, 10)
	if data != nil && len(data) > 0 {
		for k, v := range data {
			if v == nil || strings.TrimSpace(k) == "" {
				continue
			}
			_data[strings.TrimSpace(k)] = v
		}
	}
	_data["success"] = true

	msg, _ := RPCResponseMsg(req, _data)
	return msg
}

func (t *ThingsBoardMqttClientChannel) mqttRpcResponse(bytes_ []byte) {
	t.logger.Infof("[rcp-回复] %s \n", string(bytes_))
	t.mqttClient.Publish(t.protocolInfo.PublicTopic+TOPIC_RPC, byte(1), false, bytes_)
}

// rpc 处理
func (t *ThingsBoardMqttClientChannel) rpcHandle() {

	for {
		rpcRequest, ok := <-t.rcpChan

		if t.isClosed {
			break
		}

		if !ok {
			t.logger.Errorln("rpc 通道被关闭 ")
			break
		}

		if t.rcpTaskPool.IsClosed() {
			t.mqttRpcResponse(RPCResponseFailMsg(rpcRequest, "rpc 任务池已经关闭"))
			continue
		}

		deviceInfo, err1 := FindTransferDeviceByDevName(rpcRequest.Device, t)
		if err1 != nil {
			t.mqttRpcResponse(RPCResponseFailMsg(rpcRequest, fmt.Sprintf("获取设备失败 err %s", err1)))
			continue
		}

		if deviceInfo == nil {
			t.mqttRpcResponse(RPCResponseFailMsg(rpcRequest, "设备配置丢失"))
			continue
		}

		task, ok := rpcMethodMapping[rpcRequest.Data.Method]
		if !ok {
			task = rpcMethodMapping[""]
		}

		err := t.rcpTaskPool.Submit(func() {
			defer func() {
				if rerr := recover(); rerr != nil {
					t.logger.Errorf("[rpc-panic] rpc %+v 处理出错  error %s \n", rpcRequest, rerr)
					t.mqttRpcResponse(RPCResponseFailMsg(rpcRequest, fmt.Sprintf("系统出现严重问题 err %s", rerr)))
				}
			}()
			task(t, rpcRequest, deviceInfo)
		})

		if err != nil {
			t.mqttRpcResponse(RPCResponseFailMsg(rpcRequest, fmt.Sprintf("任务提交失败 err %s", err)))
		}

	}

}

type rpcTask func(t *ThingsBoardMqttClientChannel, req *RPCRequest, transferDeviceInfo *conf_table_define.DeviceInfo)

func FindTransferDeviceByDevName(transferDevName string, t *ThingsBoardMqttClientChannel) (*conf_table_define.DeviceInfo, error) {
	findNum := 0
	var dev *conf_table_define.DeviceInfo

	//根据当前通道，获取设备列表
	for _, item := range conf_table.FindAllDeviceByChlId(t.ChannelInfo.ChlId) {
		if t.protocolInfo.CommunicationAddrAsDeviceName() {
			if item.Dev_comm_addr == transferDevName {
				dev = item
				findNum++
			}
		} else if t.protocolInfo.PublicAddrAsDeviceName() {
			if item.Dev_pub_addr == transferDevName {
				dev = item
				findNum++
			}
		} else {
			if item.Dev_name == transferDevName {
				dev = item
				findNum++
			}
		}
	}

	if findNum > 1 {
		return nil, fmt.Errorf("转发设备名  %s 重复 %d", transferDevName, findNum)
	}

	if findNum <= 0 {
		return nil, fmt.Errorf("设备 %s不存在", transferDevName)
	}

	return dev, nil
}

// rpcMethodMapping rpc 方法映射
// 每个函数都会放到任务池中执行
// 每个函数都已经做了panic 处理
var rpcMethodMapping = map[string]rpcTask{

	"getTermInfo": func(t *ThingsBoardMqttClientChannel, req *RPCRequest, deviceInfo *conf_table_define.DeviceInfo) {
		t.mqttRpcResponse(RPCResponseSuccessMsg(req, map[string]interface{}{
			"OS": fmt.Sprintf("APP_VERSION %s GO_VERSION %s ", sys_contant.APP_VERSION, sys_contant.GO_VERSION),
		}))

	},

	// {"device":"箱变1号","data":{"id":3,"method":"sendCommand","params":{"command":"a"}}}
	"sendCommand": func(t *ThingsBoardMqttClientChannel, req *RPCRequest, deviceInfo *conf_table_define.DeviceInfo) {
		t.mqttRpcResponse(RPCResponseFailMsg(req, "请求处理逻辑未实现"))
	},

	"write": func(t *ThingsBoardMqttClientChannel, req *RPCRequest, deviceInfo *conf_table_define.DeviceInfo) {
		//todo
		t.mqttRpcResponse(RPCResponseFailMsg(req, "请求处理逻辑未实现"))
	},

	"timing": func(t *ThingsBoardMqttClientChannel, req *RPCRequest, deviceInfo *conf_table_define.DeviceInfo) {
		//todo
		t.mqttRpcResponse(RPCResponseFailMsg(req, "请求处理逻辑未实现"))
	},

	"read": func(t *ThingsBoardMqttClientChannel, req *RPCRequest, deviceInfo *conf_table_define.DeviceInfo) {
		//todo
		t.mqttRpcResponse(RPCResponseFailMsg(req, "请求处理逻辑未实现"))
	},

	//默认处理
	"": func(t *ThingsBoardMqttClientChannel, req *RPCRequest, deviceInfo *conf_table_define.DeviceInfo) {

		//写值, 兼容以前的版本
		if strings.HasPrefix(req.Data.Method, "set") {
			key := req.Data.Method[3:]
			val := req.Data.Params
			err := writeVal(t, deviceInfo.Dev_id, key, fmt.Sprintf("%v", val))
			if err != nil {
				t.mqttRpcResponse(RPCResponseFailMsg(req, err.Error()))
			} else {
				t.mqttRpcResponse(RPCResponseSuccessMsg(req, nil))
			}
		} else {
			t.mqttRpcResponse(RPCResponseFailMsg(req, "指令未知"))
		}

	},
}

func writeVal(t *ThingsBoardMqttClientChannel, transferDevId string, key string, val string) error {

	transferTagInfo, err := findTagInfo(t, transferDevId, key)
	if err != nil {
		return err
	}

	tagInfo, _ := conf_table.FindAllTagByTagId(transferTagInfo.Ori_tag_id)
	if tagInfo == nil {
		return fmt.Errorf("转发表异常")
	}

	byteArr, dt, err := parseWriteVal(transferTagInfo, val)

	if err != nil {
		return err
	}

	if len(byteArr) <= 0 {
		return fmt.Errorf("值为空")
	}

	var valObject storage_define.ValObject
	switch dt {
	case conf_table_define.STRING:
		valObject = storage_define.NewStringVal(tagInfo.Tag_name, string(byteArr), time.Now().UnixMilli(), storage_define.QOS_GOOD)
	case conf_table_define.UINT64:
		valObject = storage_define.NewUint64Val(tagInfo.Tag_name, binarys.BytesToUint642(byteArr), time.Now().UnixMilli(), storage_define.QOS_GOOD)
	case conf_table_define.INT64:
		valObject = storage_define.NewInt64Val(tagInfo.Tag_name, binarys.BytesToInt642(byteArr), time.Now().UnixMilli(), storage_define.QOS_GOOD)
	case conf_table_define.FLOAT64:
		valObject = storage_define.NewFloat64Val(tagInfo.Tag_name, binarys.BytesToFloat642(byteArr), time.Now().UnixMilli(), storage_define.QOS_GOOD)
	default:
		panic("mqtt rpc 异常 无法创建 ValObject")
	}

	err = t.channelManager.WriteValObject(transferTagInfo.Ori_tag_id, valObject)
	if err != nil {
		valObject.SetQos(uint8(storage_define.QOS_BAD))
	}

	storage.SaveAndNotify(valObject)

	return err
}

func findTagInfo(t *ThingsBoardMqttClientChannel, devId string, key string) (*conf_table_define.TagInfo, error) {
	keyName := strings.TrimSpace(key)
	switch t.protocolInfo.TransferKey {
	case 0: //0:测点名称 tag_name
		tagInfo, _ := conf_table.FindAllTagByName(devId, keyName)
		if tagInfo == nil {
			return nil, fmt.Errorf("%s 点位不存在", keyName)
		}
	case 1: //1:测点地址 obj_addr
		list := conf_table.FindAllTagByObjAddr(devId, keyName)
		if list == nil || len(list) <= 0 {
			return nil, fmt.Errorf("%s 点位不存在", keyName)
		} else if len(list) > 1 {
			//找出遥控或遥调的点位
			var r *conf_table_define.TagInfo
			num := 0
			for _, item := range list {
				if item.IsYk() || item.IsYt() {
					num++
					r = item
				}
			}
			if num > 1 {
				return nil, fmt.Errorf("%s 点位有%d重复个", keyName, num)
			} else if num == 0 {
				return nil, fmt.Errorf("%s 点位不存在", keyName)
			}
			return r, nil
		}
		return list[0], nil
	default: //2: 物模标识 tag_desc
		list := conf_table.FindAllTagByTagDesc(devId, keyName)
		if list == nil || len(list) <= 0 {
			return nil, fmt.Errorf("%s 点位不存在", keyName)
		} else if len(list) > 1 {
			//找出遥控或遥调的点位
			var r *conf_table_define.TagInfo
			num := 0
			for _, item := range list {
				if item.IsYk() || item.IsYt() {
					num++
					r = item
				}
			}
			if num > 1 {
				return nil, fmt.Errorf("%s 点位有%d重复个", keyName, num)
			} else if num == 0 {
				return nil, fmt.Errorf("%s 点位不存在", keyName)
			}
			return r, nil
		}
		return list[0], nil
	}
	return nil, fmt.Errorf("%s 点位不存在", keyName)
}

func parseWriteVal(tagInfo *conf_table_define.TagInfo, val string) ([]byte, int, error) {
	val = strings.TrimSpace(val)
	//字符串
	if tagInfo.DataTypeStr() == conf_table_define.DATA_TYPE_STRING {
		return []byte(val), conf_table_define.STRING, nil
	}

	//整型
	intVal, err := strconv.ParseInt(val, 10, 64)
	if err == nil {

		buf := new(bytes.Buffer)

		switch tagInfo.DataTypeStr() {

		case conf_table_define.DATA_TYPE_BIT:
			var v = byte(0)
			if intVal != 0 {
				v = 1
			}
			err = binary.Write(buf, binary.BigEndian, v)
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil

		case conf_table_define.DATA_TYPE_UINT8:
			err = binary.Write(buf, binary.BigEndian, uint8(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_INT8:
			err = binary.Write(buf, binary.BigEndian, int8(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_INT16, conf_table_define.DATA_TYPE_BCD16:
			err = binary.Write(buf, binary.BigEndian, int16(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_UINT16:
			err = binary.Write(buf, binary.BigEndian, uint16(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_INT32, conf_table_define.DATA_TYPE_BCD32:
			err = binary.Write(buf, binary.BigEndian, int32(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_UINT32:
			err = binary.Write(buf, binary.BigEndian, uint32(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_INT64:
			err = binary.Write(buf, binary.BigEndian, intVal)
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_UINT64:
			err = binary.Write(buf, binary.BigEndian, uint64(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_FLOAT32:
			err = binary.Write(buf, binary.BigEndian, float32(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.FLOAT64, nil
		case conf_table_define.DATA_TYPE_FLOAT64:
			err = binary.Write(buf, binary.BigEndian, float64(intVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %d error %s ", intVal, err)
			}
			return buf.Bytes(), conf_table_define.FLOAT64, nil
		}

	}

	//浮点型
	floatVal, err := strconv.ParseFloat(val, 64)
	if err == nil {
		buf := new(bytes.Buffer)

		switch tagInfo.DataTypeStr() {

		case conf_table_define.DATA_TYPE_BIT:
			var v = byte(0)
			if floatVal != 0 {
				v = 1
			}
			err = binary.Write(buf, binary.BigEndian, v)
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_UINT8:
			err = binary.Write(buf, binary.BigEndian, uint8(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_INT8:
			err = binary.Write(buf, binary.BigEndian, int8(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_INT16, conf_table_define.DATA_TYPE_BCD16:
			err = binary.Write(buf, binary.BigEndian, int16(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_UINT16:
			err = binary.Write(buf, binary.BigEndian, uint16(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_INT32, conf_table_define.DATA_TYPE_BCD32:
			err = binary.Write(buf, binary.BigEndian, int32(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_UINT32:
			err = binary.Write(buf, binary.BigEndian, uint32(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_INT64:
			err = binary.Write(buf, binary.BigEndian, floatVal)
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.INT64, nil
		case conf_table_define.DATA_TYPE_UINT64:
			err = binary.Write(buf, binary.BigEndian, uint64(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.UINT64, nil
		case conf_table_define.DATA_TYPE_FLOAT32:
			err = binary.Write(buf, binary.BigEndian, float32(floatVal))
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.FLOAT64, nil
		case conf_table_define.DATA_TYPE_FLOAT64:
			err = binary.Write(buf, binary.BigEndian, floatVal)
			if err != nil {
				return nil, 0, fmt.Errorf("写类型异常 %v error %s ", floatVal, err)
			}
			return buf.Bytes(), conf_table_define.FLOAT64, nil
		}
	}

	return nil, 0, fmt.Errorf("值 %s 无法转成 %s error %s", val, tagInfo.DataTypeStr(), err)
}
